#include <Kharlia/Engine/Common.h>
#include <Kharlia/Engine/Init.h>
#include <Kharlia/Engine/Resource.h>
#include <Kharlia/Core/ObjectUtil.h>

//KH_ENABLE_HELD_SHARED_PTR_FROM_PYTHON(kharlia::engine::FResourceManager)
//KH_ENABLE_HELD_SHARED_PTR_FROM_PYTHON(kharlia::engine::FResource)
//KH_ENABLE_HELD_SHARED_PTR_FROM_PYTHON(kharlia::engine::FTexture)

namespace kharlia { namespace engine {

struct FResourceIter {
    shared_ptr<FResourceManager> ResourceManager;
    FResourceManager::ResourceMap::const_iterator Iterator;

    object Next() {
        object r;
        while(r.is_none())
            r = NextImpl();
        return r;
    }
    object NextImpl() {
        if (Iterator == ResourceManager->GetResources().end()) {
            PyErr_SetNone(PyExc_StopIteration);
            py::throw_error_already_set();
        }
        object r = object(Iterator->second.lock());
        Iterator++;
        return r;
    }
};

object FResourceManager::MakeIter(shared_ptr<FResourceManager> self) {
    FResourceIter it;
    it.ResourceManager = self;
    it.Iterator = self->GetResources().begin();
    return object(it);
}

void _InitResourceBindings() {
    class_<FResourceManager, shared_ptr<FResourceManager>, noncopyable>
        ("FResourceManager", init<>())
        .def("GetResource", &FResourceManager::GetResource)
        .def("CreateResource", &FResourceManager::CreateResource, (arg("cls"), arg("name")))
        .def("MakeIter", &FResourceManager::MakeIter)
        .staticmethod("MakeIter")
        ;
    // Iteration set up in engine.__init__

    class_<FResourceIter>
        ("FResourceManagerIterator", no_init)
        .def("next", &FResourceIter::Next)
        ;

    class_<FResource, shared_ptr<FResource>, noncopyable>
        ("FResource", no_init)
        .add_property("Name", &FResource::GetName)
        .add_property("ManualLoad", &FResource::GetManualLoad)
        .add_property("CanLoad", &FResource::GetCanLoad)
        .add_property("IsLoaded", &FResource::GetIsLoaded)
        .add_property("InnerID", &FResource::GetInnerID)
        .def("Load", pure_virtual(&FResource::Load))
        .def("Unload", pure_virtual(&FResource::Unload))
        //.def_pickle(FResourcePickler())
        ;

    class_<FTexture, shared_ptr<FTexture>, bases<FResource>, noncopyable>
        ("FTexture", init<str>())
        //.def_readwrite("Client", &FTexture::mClient)
        .add_property("IsValid", &FTexture::GetIsValid)
        .add_property("Width", &FTexture::GetWidth)
        .add_property("Height", &FTexture::GetHeight)
        .add_property("SrcSize", &FTexture::GetSrcSize)
        .def("Load", &FTexture::Load)
        .def("Unload", &FTexture::Unload)
        .def_pickle(FTexturePickler())
        ;

    // This has to be held by a shared_ptr in order to properly create a weak_ptr to it
    class_<CSpriteAniDef, shared_ptr<CSpriteAniDef>, bases<core::CObject, FResource>, noncopyable>
        ("CSpriteAniDefBase", init<str>())
        .add_property("ShouldLoop", &CSpriteAniDef::GetShouldLoop)
        .add_property("FrameListCount", &CSpriteAniDef::GetFrameListCount)
        //.add_property("Engine", make_function(&CSpriteAniDef::GetEngine, return_value_policy<return_by_value>()), &CSpriteAniDef::SetEngine)
        .def("GetFrameCount", &CSpriteAniDef::GetFrameCount)
        .def("GetFrame", &CSpriteAniDef::GetFramePy)
        ;
}

}}